package com.hok.misc.file.transmission;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.nio.charset.Charset;
import java.util.Iterator;

public class NIOServer {
	private Selector socketSelector = null;
	private ServerSocketChannel ssChannel = null;
	private SocketChannel socketChannel = null;
	private static SelectionKey key = null;
	private int port = 5512;
	private int backlog = 100;
	private Charset charset = Charset.defaultCharset();
	private ByteBuffer shareBuffer = ByteBuffer.allocate(1024);// 生成1kb的缓冲区,可以根据实际情况调的更大些

	public NIOServer() {
		try {
			socketSelector = SelectorProvider.provider().openSelector();
			ssChannel = ServerSocketChannel.open();
			ssChannel.socket().bind(new InetSocketAddress(port), 100);
			System.out.println(String.format("NIO服务器启动,监听端口%1$s,最大连接数%2$s", port, backlog));
		} catch (IOException e) {
			throw new ExceptionInInitializerError(e);
		}
	}

	/**
	 * 接收客户端连接
	 */
	public void acceptConnect() {
		while (true) {
			try {
				SocketChannel socketChannel = ssChannel.accept();// 阻塞模式，直到有连接进入
				System.out.println("收到客户机连接，来自:" + ssChannel.socket().getInetAddress());
				socketChannel.configureBlocking(false);// 设置非阻塞模式
				synchronized (this) {
					socketSelector.wakeup();
					socketChannel.register(socketSelector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 读写服务
	 * 
	 * @throws IOException
	 */
	public void service() throws IOException {
		while (true) {
			synchronized (this) {// 空的同步块，目的是为了避免死锁
			}
			if (!(socketSelector.select() > 0)) {
				continue;
			}
			Iterator<SelectionKey> it = socketSelector.selectedKeys().iterator();
			while (it.hasNext()) {
				key = it.next();
				it.remove();
				if (key.isReadable()) {// 读就绪
					this.readDataFromSocket(key);
				}
				if (key.isWritable()) {// 写就绪
					this.sayWelcome(key);
				}
			}
		}
	}

	// 读取客户机发来的数据
	private void readDataFromSocket(SelectionKey key) throws IOException {
		shareBuffer.clear();// 清空buffer
		socketChannel = (SocketChannel) key.channel();
		int num = 0;
		while ((num = socketChannel.read(shareBuffer)) > 0) {
			shareBuffer.flip();// 将当前极限设置为位置，并把设置后的位置改为0
		}
		if (num == -1) {// 读取流的未尾，对方已关闭流
			socketChannel.close();
			return;
		}
		System.out.println("client request:"
				+ charset.decode(shareBuffer).toString());
	}

	// 向客户机发响应信息
	private void sayWelcome(SelectionKey key) throws IOException {
		shareBuffer.clear();// 清空buffer
		socketChannel = (SocketChannel) key.channel();
		shareBuffer
				.put("Welcome to china!this is a greate and very beautifual country!\n"
						.getBytes());
		shareBuffer.flip();// 将当前极限设置为位置，并把设置后的位置改为0
		socketChannel.write(shareBuffer);
	}

	// Main方法
	public static void main(String[] args) {
		final NIOServer server = new NIOServer();
		Runnable task = new Runnable() {
			public void run() {
				server.acceptConnect();
			}
		};
		new Thread(task).start();// 启动处理客户机连接的线程
		try {
			server.service();
		} catch (IOException e) {// 发生IO流异常时，关闭对应的socket
			try {
				key.channel().close();
				key.cancel();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}
}